package qj.tool.db.orientdb;

import java.util.Collection;
import java.util.HashMap;

import qj.util.funct.F1;
import qj.util.funct.F2;
import qj.util.funct.P2;

import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
import com.orientechnologies.orient.core.index.OIndex;
import com.orientechnologies.orient.core.record.impl.ODocument;

@SuppressWarnings("rawtypes")
public class DbHooks {
	HashMap<String, F2<ODocument, ODatabaseDocumentTx, Boolean>> beforeCreates = new HashMap<String, F2<ODocument, ODatabaseDocumentTx, Boolean>>();
	HashMap<String, F2<ODocument, ODatabaseDocumentTx, Boolean>> beforeDeletes = new HashMap<String, F2<ODocument, ODatabaseDocumentTx, Boolean>>();
	HashMap<String, P2<ODocument, ODatabaseDocumentTx>> afterCreates = new HashMap<String, P2<ODocument, ODatabaseDocumentTx>>();
	
	public <A> void addIndexUnique(final String indexName, String clazz, final F1<ODocument, String> valF) {
		beforeCreates.put(clazz, new F2<ODocument, ODatabaseDocumentTx, Boolean>() {public Boolean e(ODocument doc, ODatabaseDocumentTx ds) {
			String val = valF.e(doc);
			Object existedVal = ds.getMetadata().getIndexManager().getIndex(indexName).get(val);
			
			if (existedVal == null) {
				return true;
			}
			if (existedVal instanceof Collection) {
				return ((Collection) existedVal).size() == 0;
			} else {
				return false;
			}
		}});
		
		beforeDeletes.put(clazz, new F2<ODocument, ODatabaseDocumentTx, Boolean>() {public Boolean e(ODocument doc, ODatabaseDocumentTx ds) {
			String val = valF.e(doc);
			OIndex<?> index = ds.getMetadata().getIndexManager().getIndex(indexName);
			index.remove(val);
			return true;
		}});
		
		afterCreates.put(clazz, new P2<ODocument, ODatabaseDocumentTx>() {public void e(ODocument doc, ODatabaseDocumentTx ds) {
			String val = valF.e(doc);
			ds.getMetadata().getIndexManager().getIndex(indexName).put(val, doc.getIdentity());
		}});
	}

	public boolean onBeforeCreate(ODocument doc, ODatabaseDocumentTx ds) {
		F2<ODocument, ODatabaseDocumentTx, Boolean> validateF = beforeCreates.get(doc.getClassName());
		if (validateF != null) {
			return validateF.e(doc, ds);
		}
		return true;
	}

	public void onAfterCreate(ODocument doc, ODatabaseDocumentTx ds) {
		P2<ODocument, ODatabaseDocumentTx> afterCreateF = afterCreates.get(doc.getClassName());
		if (afterCreateF != null) {
			afterCreateF.e(doc, ds);
		}
	}

	public boolean onBeforeDelete(ODocument doc, ODatabaseDocumentTx ds) {
		F2<ODocument, ODatabaseDocumentTx, Boolean> validateF = beforeDeletes.get(doc.getClassName());
		if (validateF != null) {
			return validateF.e(doc, ds);
		}
		return true;
	}
	
}
